package utils.fileConvert;

import com.alibaba.fastjson.JSONObject;
import com.lkx.util.ExcelParam;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.*;
import org.springframework.web.multipart.MultipartFile;
import utils.object.UtilValidate;
import utils.string.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 文本转换工具类
 *
 * @author Chen Yuan
 * @create 2022-01-04  15:54
 */
public class TextConvertUtil {

//	------------  中文转拼音 ----------------

	/**
	 * 中文转全拼
	 *
	 * @param targetText 待转换文字
	 * @param lowerCase  是否小写, (true:小写 , false:大写)
	 * @param tone       音标形式, (1/空:无, 2:音标, 3:用对应数字) Constants.PY_TONE_TYPE
	 * @param separate   分隔符
	 * @param retain     是否保留中文之外的 符号/字母
	 * @return 转换后的拼音
	 */
	public static String convertChineseToPy(String targetText, boolean lowerCase, int tone, String separate, boolean retain) {
		String result = "";
		try {
			HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();

			// 设置大小写
			HanyuPinyinCaseType caseType = lowerCase ? HanyuPinyinCaseType.LOWERCASE : HanyuPinyinCaseType.UPPERCASE;
			format.setCaseType(caseType);
			// 将 u 转换成 v 输出
			format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);
			// 设置声调 (WITH_TONE_MARK:音标 , WITH_TONE_NUMBER:用对应数字标识 , WITHOUT_TONE:无)
			if (tone == 2) {
				format.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);
			} else if (tone == 3) {
				format.setToneType(HanyuPinyinToneType.WITH_TONE_NUMBER);
			} else {
				format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
			}


			result = PinyinHelper.toHanYuPinyinString(targetText, format, separate, retain);
		} catch (Exception e) {
			//log.error("××××  ×× {} ××××××××××\n  ", e.getMessage(), e);
		}
		return result;
	}

	/**
	 * 获取首字母
	 *
	 * @param targetText 带转换文本
	 * @param lowerCase  是否小写, (true:小写 , false:大写)
	 * @param separate   分隔符
	 * @param retain     是否保留中文之外的 符号/字母
	 * @return 转换后的拼音首字母
	 */
	public static String convertChineseToPyInitials(String targetText, boolean lowerCase, String separate, boolean retain) {
		return convertChineseToPyInitials(targetText, lowerCase, separate, retain, true);
	}

	/**
	 * 将数组中的某个字段转为拼音  全拼
	 *
	 * @param dataList  数组
	 * @param titleMap  (key:需要转换的字段名称, value:存放转换后字符的字段) , value 可为空, 默认为 key+"PY"
	 * @param clazz     输入数组对象类型
	 * @param lowerCase 是否小写, true:小写, false:大写
	 * @param tone      音标形式, (1/空:无, 2:音标, 3:用对应数字) Constants.PY_TONE_TYPE
	 * @param separate  分隔符
	 * @param retain    是否保留中文之外的 符号/字母
	 */
	public static <T> List<T> convertListToPy(List<T> dataList, Map<String, String> titleMap, Class<T> clazz,
	                                          boolean lowerCase, int tone, String separate, boolean retain) {
		return convertListToPy(dataList, titleMap, clazz, false, lowerCase, tone, separate, retain);
	}

	/**
	 * 将数组中的某个字段转为拼音  首字母
	 *
	 * @param dataList  数组
	 * @param titleMap  (key:需要转换的字段名称, value:存放转换后字符的字段) , value 可为空, 默认为 key+"PY"
	 * @param clazz     输入数组对象类型
	 * @param lowerCase 是否小写, true:小写, false:大写
	 * @param separate  分隔符
	 * @param retain    是否保留中文之外的 符号/字母
	 */
	public static <T> List<T> convertListToPyInitials(List<T> dataList, Map<String, String> titleMap, Class<T> clazz,
	                                                  boolean lowerCase, String separate, boolean retain) {
		return convertListToPy(dataList, titleMap, clazz, true, lowerCase, 1, separate, retain);
	}

	/**
	 * 读取 Excel, 并将其中指定列的 中文转拼音
	 *
	 * @param response  请求响应
	 * @param file      文件流
	 * @param titleMap  map-(key:目标标题名, value:拼音信息列的标题名) 映射关系, key 必填, value 可以为空, value 默认 key+"PY"
	 * @param lowerCase 是否小写, (true:小写 , false:大写)
	 * @param tone      音标形式, (1/空:无, 2:音标, 3:用对应数字) Constants.PY_TONE_TYPE
	 * @param separate  转成拼音后分隔符
	 * @param retain    是否保留中文之外的 符号/字母
	 */
	public static void convertExcelToPy(HttpServletResponse response, MultipartFile file, Map<String, String> titleMap,
	                                    boolean lowerCase, int tone, String separate, boolean retain) throws Exception {
		ExcelParam excelParam = new ExcelParam();
		excelParam.setClazz(JSONObject.class);
		excelParam.setStream(true);
		excelParam.setBuf(file.getBytes());
		//excelParam.setRowNumIndex(titleRowIndex);
		List<JSONObject> dataList = ExcelUtilBase.commonReadExcel(excelParam);

		dataList = convertListToPy(dataList, titleMap, JSONObject.class, lowerCase, tone, separate, retain);

		Map map = excelParam.getMap();
		Set<String> keySet = titleMap.keySet();
		for (String key : keySet) {
			String value = titleMap.get(key);
			if (UtilValidate.isEmpty(value)) {
				value = key + "PY";
			}
			map.put(value, value);
		}

		ExcelUtil.exportExcelOutputStream(response, map, dataList, JSONObject.class, file.getName());
	}

	/**
	 * 读取 Excel, 并将其中指定列的 中文转拼音
	 *
	 * @param response  请求响应
	 * @param file      文件流
	 * @param titleMap  map-(key:目标标题名, value:拼音信息列的标题名) 映射关系, key 必填, value 可以为空, value 默认 key+"PY"
	 * @param lowerCase 是否小写, (true:小写 , false:大写)
	 * @param separate  转成拼音后分隔符
	 * @param retain    是否保留中文之外的 符号/字母
	 */
	public static void convertExcelToPyInitials(HttpServletResponse response, MultipartFile file, Map<String, String> titleMap,
	                                            boolean lowerCase, String separate, boolean retain) throws Exception {
		ExcelParam excelParam = new ExcelParam();
		excelParam.setClazz(JSONObject.class);
		excelParam.setStream(true);
		excelParam.setBuf(file.getBytes());
		//excelParam.setRowNumIndex(titleRowIndex);
		List<JSONObject> dataList = ExcelUtilBase.commonReadExcel(excelParam);

		dataList = convertListToPyInitials(dataList, titleMap, JSONObject.class, lowerCase, separate, retain);

		Map map = excelParam.getMap();
		Set<String> keySet = titleMap.keySet();
		for (String key : keySet) {
			String value = titleMap.get(key);
			if (UtilValidate.isEmpty(value)) {
				value = key + "PY";
			}
			map.put(value, value);
		}

		ExcelUtil.exportExcelOutputStream(response, map, dataList, JSONObject.class, file.getName());
	}

	/**
	 * 读取 Excel, 并将其中指定列的 中文转拼音
	 *
	 * @param outFilePath 导出文件地址
	 * @param file        文件流
	 * @param titleMap    map-(key:目标标题名, value:拼音信息列的标题名) 映射关系, key 必填, value 可以为空, value 默认 key+"PY"
	 * @param lowerCase   是否小写, (true:小写 , false:大写)
	 * @param tone        音标形式, (1/空:无, 2:音标, 3:用对应数字) Constants.PY_TONE_TYPE
	 * @param separate    转成拼音后分隔符
	 * @param retain      是否保留中文之外的 符号/字母
	 */
	public static void convertExcelToPy(String outFilePath, MultipartFile file, Map<String, String> titleMap,
	                                    boolean lowerCase, int tone, String separate, boolean retain) throws Exception {
		ExcelParam excelParam = new ExcelParam();
		excelParam.setClazz(JSONObject.class);
		excelParam.setStream(true);
		excelParam.setBuf(file.getBytes());
		List<JSONObject> dataList = ExcelUtilBase.commonReadExcel(excelParam);

		dataList = convertListToPy(dataList, titleMap, JSONObject.class, lowerCase, tone, separate, retain);

		Map map = excelParam.getMap();
		Set<String> keySet = titleMap.keySet();
		for (String key : keySet) {
			String value = titleMap.get(key);
			if (UtilValidate.isEmpty(value)) {
				value = key + "PY";
			}
			map.put(value, value);
		}

		ExcelUtil.exportExcel(outFilePath, excelParam.getMap(), dataList, JSONObject.class, file.getName());
	}

	/**
	 * 读取 Excel, 并将其中指定列的 中文转拼音
	 *
	 * @param outFilePath 导出文件地址
	 * @param file        文件流
	 * @param titleMap    map-(key:目标标题名, value:拼音信息列的标题名) 映射关系, key 必填, value 可以为空, value 默认 key+"PY"
	 * @param lowerCase   是否小写, (true:小写 , false:大写)
	 * @param separate    转成拼音后分隔符
	 * @param retain      是否保留中文之外的 符号/字母
	 */
	public static void convertExcelToPyInitials(String outFilePath, MultipartFile file, Map<String, String> titleMap,
	                                            boolean lowerCase, String separate, boolean retain) throws Exception {
		ExcelParam excelParam = new ExcelParam();
		excelParam.setClazz(JSONObject.class);
		excelParam.setStream(true);
		excelParam.setBuf(file.getBytes());
		List<JSONObject> dataList = ExcelUtilBase.commonReadExcel(excelParam);

		dataList = convertListToPyInitials(dataList, titleMap, JSONObject.class, lowerCase, separate, retain);

		Map map = excelParam.getMap();
		Set<String> keySet = titleMap.keySet();
		for (String key : keySet) {
			String value = titleMap.get(key);
			if (UtilValidate.isEmpty(value)) {
				value = key + "PY";
			}
			map.put(value, value);
		}

		ExcelUtil.exportExcel(outFilePath, excelParam.getMap(), dataList, JSONObject.class, file.getName());
	}


// =========== 私有方法 =================

	/**
	 * 获取首字母, 递归调用的方法
	 *
	 * @param targetText          带转换文本
	 * @param lowerCase           是否小写, (true:小写 , false:大写)
	 * @param separate            分隔符
	 * @param retain              是否保留中文之外的 符号/字母
	 * @param constantPlaceholder 本次递归是否需要解析占位符
	 * @return 转换后的拼音首字母
	 */
	private static String convertChineseToPyInitials(String targetText, boolean lowerCase, String separate, boolean retain, boolean constantPlaceholder) {
		StringBuilder stringBuilder = new StringBuilder();

		Map<String, String> placeholderMap = new HashMap<>(20);

		String placeholderPre = "#{";
		String tempSeparate = "-!-";
		String temp = targetText;

		if (separate == null) {
			separate = "";
		}

		if (constantPlaceholder) {
			String placeholderSuf1 = "啊", placeholder;
			String placeholderSuf2 = TextConvertUtil.convertChineseToPy(placeholderSuf1, lowerCase, 3, "", false);

			//判断是否为汉字
			for (int i = 0; i < targetText.length(); ++i) {
				char current = targetText.charAt(i);
				//判断是否为汉字
				if (Character.toString(current).matches("[\\u4E00-\\u9FA5]+")) {
					stringBuilder.append(current);
					continue;
				}

				if (retain) {
					// 将中文的占位符放入待转换字符串
					placeholder = placeholderPre + i + placeholderSuf1;
					stringBuilder.append(placeholder);
					// 将 "啊" 转换后的 "a" 存入 Map, 这样方便后面的对照, 替换占位符
					placeholder = placeholderPre + i + placeholderSuf2;
					placeholderMap.put(placeholder, String.valueOf(current));
				}
			}

			// 将带有占位符的字符串替换原字符串
			targetText = stringBuilder.toString();
			// 初始化 stringBuilder
			stringBuilder = new StringBuilder();

			// 自定义乱码分隔符, 并按照该分隔符进行转换, 然后分割出单个字的拼音
			temp = TextConvertUtil.convertChineseToPy(targetText, lowerCase, 3, tempSeparate, true);
		}

		String[] split = temp.split(tempSeparate);

		// 用于存放首字母
		String initial;
		// 遍历分割后的数组, 获取首字母, 并将占位符的符号替换回去
		for (String word : split) {
			// 如果当前部分包含占位符前缀, 则表示当前是占位符
			if (word.contains(placeholderPre)) {
				initial = placeholderMap.get(word);
			} else if (StringUtil.containNumber(word)) {
				word = StringUtil.splitByNumber(word, tempSeparate);
				initial = convertChineseToPyInitials(word, lowerCase, separate, retain, false);
			} else {
				initial = word.substring(0, 1);
			}
			stringBuilder.append(initial).append(separate);
		}

		int sepLength = separate.length();
		if (sepLength <= 0) {
			return stringBuilder.toString();
		} else {
			return stringBuilder.deleteCharAt(stringBuilder.length() - sepLength).toString();
		}
	}

	/**
	 * 将数组中的某个字段转为拼音  基本方法
	 *
	 * @param dataList  数组
	 * @param titleMap  (key:需要转换的字段名称, value:存放转换后字符的字段) , value 可为空, 默认为 key+"PY"
	 * @param initials  是否只获取首字母, true:首字母, false:全拼
	 * @param clazz     输入数组对象类型
	 * @param lowerCase 是否小写, true:小写, false:大写
	 * @param tone      音标形式, (1/空:无, 2:音标, 3:用对应数字) Constants.PY_TONE_TYPE
	 * @param separate  分隔符
	 * @param retain    是否保留中文之外的 符号/字母
	 */
	private static <T> List<T> convertListToPy(List<T> dataList, Map<String, String> titleMap, Class<T> clazz, boolean initials,
	                                           boolean lowerCase, int tone, String separate, boolean retain) {
		List<T> result = new LinkedList<>();
		if (dataList.size() <= 0 || titleMap.size() <= 0) {
			return dataList;
		}

		List<JSONObject> tempList = BeanMapperUtils.mapList(dataList, JSONObject.class);
		Set<String> keySet = titleMap.keySet();
		String pyField, py;
		for (JSONObject object : tempList) {
			for (String key : keySet) {
				pyField = titleMap.get(key);
				Object valueObj = object.get(key);
				if (UtilValidate.isEmpty(valueObj)) {
					continue;
				}

				if (initials) {
					py = TextConvertUtil.convertChineseToPyInitials(String.valueOf(valueObj), lowerCase, separate, retain);
				} else {
					py = TextConvertUtil.convertChineseToPy(String.valueOf(valueObj), lowerCase, tone, separate, retain);
				}
				if (UtilValidate.isEmpty(pyField) || pyField.length() <= 0) {
					pyField = key + "PY";
				}
				object.put(pyField, py);
			}

			T data = BeanMapperUtils.map(object, clazz);
			result.add(data);
		}

		return result;
	}


// =========== 测试 =================

	public static void main(String[] args) throws Exception {
		String res = "";
		String str = "#{1a挨家挨户,挨打 | 把关,刀把 | 折纸,折本 | 湖泊,漂泊 | abd （ ￥";
		String str2 = "脊髓康复科";

		String pathOfXls = "C:/Users/zovan/Desktop/test1.xlsx";
		String pathOfXls2 = "C:/Users/zovan/Desktop/test2.xlsx";

		// 1. 中文转全拼
		//res = TextConvertUtil.convertChineseToPy(str2, false, 3, ",", false);

		// 2. 中文转首字母
		//res = TextConvertUtil.convertChineseToPyInitials(str2, true, "", true);

		// 3. 读入 Excel ，转拼音后 输出 Excel
		//File file = null;
		//FileInputStream inputStream = null;
		//MultipartFile multipartFile = null;
		//file = new File(pathOfXls);
		//inputStream = new FileInputStream(file);
		//multipartFile = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
		//TextConvertUtil.convertExcelToPy(pathOfXls2, multipartFile, ImmutableMap.of("开单科室", "", "执行科室", ""),false, 2, " ", false);

		System.out.println(res);

	}
}
